﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Dapper;

using Dapper.Library;
using System.Linq;

namespace Dapper.Library
{
    /// <summary>
    /// 指令
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class Command<T> : AbstractSet, ICommand<T>
    {
   
        public readonly IDbConnection DbCon;
        public readonly IDbTransaction DbTransaction;

        protected DataBaseContext<T> SetContext { get; set; }

        protected Command(IDbConnection conn, SqlProvider sqlProvider)
        {
            SqlProvider = sqlProvider;
            DbCon = conn;
        }

        /// <summary>
        /// 回收信息
        /// </summary>
        private void Recovery()
        {
            SqlProvider.Params = new DynamicParameters();
            SqlProvider.JoinList = new List<JoinAssTable>();
            SqlProvider.AsTableNameDic = new Dictionary<Type, string>();
        }

        protected Command(IDbConnection conn, SqlProvider sqlProvider, IDbTransaction dbTransaction)
        {
            SqlProvider = sqlProvider;
            DbCon = conn;
            DbTransaction = dbTransaction;
        }

        public int Update(T entity, string[] excludeFields = null)
        {
            int result = -1;

            SqlProvider.FormatUpdate(entity, excludeFields);
            result= DbCon.Execute(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            Recovery();
            return result;
        }

		public int Update(IEnumerable<T> entities, string[] excludeFields = null, int timeout = 120)
		{

            int result = -1;
            SqlProvider.FormatUpdate(entities.FirstOrDefault(), excludeFields, true);
			//批量修改不需要别名（暂时有点小bug，先勉强使用下）
			SqlProvider.SqlString = SqlProvider.SqlString.Replace("Update_", "").Replace("_0","").Replace("_1", "");
			var sPrimarykey = EntityCache.QueryEntity(typeof(T)).Primarykey;
			SqlProvider.SqlString += $" AND {sPrimarykey}={SqlProvider.ProviderOption.ParameterPrefix + sPrimarykey}";
            result = DbCon.Execute(SqlProvider.SqlString, entities, DbTransaction, timeout);

            Recovery();
            return result;
        }

		public async Task<int> UpdateAsync(T entity)
        {
            int result = -1;

            SqlProvider.FormatUpdate(entity, null);
            result= await DbCon.ExecuteAsync(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            Recovery();
            return result;
        }

        public int Update(Expression<Func<T, T>> updateExpression)
        {
            int result = -1;

            SqlProvider.FormatUpdate(updateExpression);
            result=DbCon.Execute(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            Recovery();
            return result;
        }

        public async Task<int> UpdateAsync(Expression<Func<T, T>> updateExpression)
        {
            int result = -1;

            SqlProvider.FormatUpdate(updateExpression);
            result= await DbCon.ExecuteAsync(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            Recovery();
            return result;
        }

        public int Delete()
        {
            int result = -1;

            SqlProvider.FormatDelete();
            result= DbCon.Execute(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            Recovery();
            return result;
        }

        public async Task<int> DeleteAsync()
        {
            int result = -1;

            SqlProvider.FormatDelete();
            result = await DbCon.ExecuteAsync(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            Recovery();
            return result;
        }

        public int Insert(T entity, string[] excludeFields = null)
        {
            int result = -1;

            SqlProvider.FormatInsert(entity, excludeFields);
            result= DbCon.Execute(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            Recovery();
            return result;
        }

        public async Task<int> InsertAsync(T entity, string[] excludeFields = null)
        {
            int result = -1;

            SqlProvider.FormatInsert(entity, excludeFields);
            result= await DbCon.ExecuteAsync(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            Recovery();
            return result;
        }

        public int InsertIdentity(T entity, string[] excludeFields = null)
        {
            int resultInfo = -1;

            SqlProvider.FormatInsertIdentity(entity, excludeFields);
            object result= DbCon.ExecuteScalar(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);
            resultInfo= result != null ? Convert.ToInt32(result) : 0;

            Recovery();
            return resultInfo;
        }

		public int Insert(IEnumerable<T> entities, string[] excludeFields = null, int timeout = 120)
		{
            int result = -1;

            SqlProvider.FormatInsert(entities.FirstOrDefault(), excludeFields);
            result= DbCon.Execute(SqlProvider.SqlString, entities, DbTransaction, timeout);

            Recovery();
            return result;
        }

        public async Task<int> InsertAsync(IEnumerable<T> entities, string[] excludeFields = null, int timeout = 120)
        {
            int result = -1;

            SqlProvider.FormatInsert(entities.FirstOrDefault(), excludeFields);
            result= await DbCon.ExecuteAsync(SqlProvider.SqlString, entities, DbTransaction, timeout);

            Recovery();
            return result;
        }

        /// <summary>
        /// 非查询功能
        /// </summary>
        /// <returns></returns>
        public int ExecuteNoQuery()
        {
            int result = -1;

            SqlProvider.FormatExecuteNoQuery();
            result = DbCon.Execute(SqlProvider.SqlString, SqlProvider.Params, DbTransaction);

            return result;
        }
    }
}
